/*
 * sintatico.cpp
 *
 *  Created on: 10/10/2012
 *      Author: wx
 */

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
#include "token.h"
//#include "tabelasimbolo.h"
#include "sintatico.h"

sintatico::sintatico() {
	tamtoklist = 0;
	conttok = 0;
	erro_compila = false;
}

void sintatico::erro(string um, string outro) {
	cout << "Erro: linha " << entrada_tokens[conttok].getLinha()
			<< " encontrado " + um + " esperado: " + outro << endl;
	if (!erro_compila)
		erro_compila = true;
}

void sintatico::found(string achado) {
	cout << "Token " + achado + " encontrado." << endl;
}

void sintatico::analisarsintatico(vector<token> copiar) {
	entrada_tokens = copiar;
	tamtoklist = 0;
	conttok = 0;
	tamtoklist = entrada_tokens.size();
	program();
	return;
}

void sintatico::program() {
	string program("program");
	token tokatual = entrada_tokens[conttok];
	string novastring;

	if (tokatual.nomeigual(program)) {
		conttok++;
		found("program");
	} else {
		erro(tokatual.getNome(), "program");
		return;
	}

	tokatual = entrada_tokens[conttok];
	if (tokatual.classetostring() == "identificador") {
		conttok++;
		found("identificador: " + tokatual.getNome());
		corpo();
	} else {
		erro(tokatual.getNome(), "tipo identificador");
	}
	tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual(".")) {
		found(".");
		cout << ">> fim da analise";
		if (!erro_compila)
			cout << " sem erros.";
		else
			cout << ". problemas foram encontrados.";
		cout << endl;
	} else {
		erro(tokatual.getNome(), ".");
	}

	return;
}

void sintatico::corpo() {
	token tokatual = entrada_tokens[conttok];

	dc();
	tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("begin")) {
		conttok++;
		found("begin");
		tokatual = entrada_tokens[conttok];
	} else {
		erro(tokatual.getNome(), "begin");
	}
	comandos();
	tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("end")) {
		conttok++;
		found("end");
		tokatual = entrada_tokens[conttok];
	} else {
		erro(tokatual.getNome(), "end");
	}
	return;
}
void sintatico::dc() {
	//<dc_v> <mais_dc> | <dc_p> <mais_dc> |lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.getNome() == "var") {
		dc_v();
		tokatual = entrada_tokens[conttok];
		if (tokatual.getNome() == ";") {
			found(";");
			mais_dc();
		} else {
			erro(tokatual.getNome(), ";");
		}
	} else if (tokatual.getNome() == "procedure") {
		dc_p();
		tokatual = entrada_tokens[conttok];
		if (tokatual.getNome() == ";") {
			found(";");
			mais_dc();
		} else {
			erro(tokatual.getNome(), ";");
		}
	}
	return;
}

void sintatico::mais_dc() {
	//; <dc> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.getNome() == ";") {
		cout << "goto dc" << endl;
		conttok++;
		dc();
	}
	return;
}

void sintatico::dc_v() {
	//var <variaveis> : <tipo_var>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("var")) {
		found("var");
		conttok++;
	} else {
		erro(tokatual.getNome(), "var");
	}
	tokatual = entrada_tokens[conttok];
	if (tokatual.classetostring() == "identificador") {
		variaveis();
	} else {
		erro(tokatual.getNome(), "tipo identificador");
	}

	tokatual = entrada_tokens[conttok];
	if (tokatual.getNome() == ":") {
		conttok++;
		tipo_var();
	} else {
		erro(tokatual.getNome(), ":");
		return;
	}
	return;
}

void sintatico::tipo_var() {
	//real | inteiro
	token tokatual = entrada_tokens[conttok];

	conttok++;

	if (tokatual.nomeigual("real")) {
		found("real");
	} else if (tokatual.nomeigual("inteiro")) {
		found("inteiro");
	} else {
		erro(tokatual.getNome(), "real ou inteiro");
	}
	return;
}

void sintatico::variaveis() {
	//ident <mais_var>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.classetostring() == "identificador") {
		found("identificador: " + tokatual.getNome());

		conttok++;
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual(",")) {
			found(",");
			mais_var();
		}
	} else {
		erro(tokatual.getNome(), " identificador");
	}

	return;
}

void sintatico::mais_var() {
	// , <variaveis> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual(",")) {
		conttok++;
		tokatual = entrada_tokens[conttok];
		if (tokatual.classetostring() == "identificador") {
			variaveis();
		} else {
			erro(tokatual.getNome(), "identificador");
		}
	}
	return;
}

void sintatico::dc_p() {
	//procedure ident <parametros> <corpo_p>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("procedure")) {
		found("procedure");
		conttok++;
		tokatual = entrada_tokens[conttok];
		if (tokatual.classetostring() == "identificador") {
			found("identificador");
			conttok++;



			tokatual = entrada_tokens[conttok];
			parametros();
			if (tokatual.nomeigual("var"))
				corpo_p();
			else
				erro(tokatual.getNome(), "var");
		} else {
			erro(tokatual.getNome(), "tipo identificador");
		}
	} else {
		erro(tokatual.getNome(), "procedure");
	}
	return;
}
void sintatico::parametros() {
	// (<lista_par>) | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("(")) {
		conttok++;
		lista_par();
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual(")"))
			conttok++;
		else
			erro(tokatual.getNome(), ")");
	}
	return;
}

void sintatico::lista_par() {
	// <variaveis> : <tipo_var> <mais_par>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.classetostring() == "identificador") {
		conttok++;
		variaveis();
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual(":")) {
			conttok++;
			found(":");
			tipo_var();
			mais_par();
		} else
			erro(tokatual.getNome(), ":");
	}

	return;
}

void sintatico::mais_par() {
	// ; <lista_par> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual(";")) {
		conttok++;
		lista_par();
	}
	return;
}

void sintatico::corpo_p() {
// <dc_loc> begin <comandos> end
	token tokatual = entrada_tokens[conttok];

	dc_loc();
	tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("begin")) {
		conttok++;
		found("begin");
		tokatual = entrada_tokens[conttok];
	} else {
		erro(tokatual.getNome(), "begin");
		return;
	}
	comandos();

	tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("end")) {
		conttok++;
		found("end");
		tokatual = entrada_tokens[conttok];
	} else {
		erro(tokatual.getNome(), "end");
	}

	return;
}

void sintatico::dc_loc() {
	// <dc_v> <mais_dcloc> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("var")) {
		dc_v();
		mais_dcloc();
	}
	return;
}

void sintatico::mais_dcloc() {
	//; <dc_loc> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual(";")) {
		conttok++;
		found(";");
		dc_loc();
	}

	return;
}

void sintatico::lista_arg() {
	// (<argumentos>) | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("(")) {
		found("(");
		conttok++;
		argumentos();
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual(")")) {
			found(")");
			conttok++;
		} else
			erro(tokatual.getNome(), ")");
	}

	return;
}
void sintatico::argumentos() {
	// ident <mais_ident>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.classetostring() == "identificador") {
		found("tipo identificador: " + tokatual.getNome());
		conttok++;
		mais_ident();
	} else
		cout << "> sem argumentos." << endl;
	return;
}

void sintatico::mais_ident() {
	//  ; <argumentos> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual(";")) {
		found(";");
		conttok++;
		argumentos();
	}

	return;
}

void sintatico::pfalsa() {
	// else <comandos> | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("else")) {
		found("else");
		conttok++;
		comandos();
	}
	return;
}

void sintatico::comandos() {
	//<comando> <mais_comandos>
	token tokatual = entrada_tokens[conttok];
	if (tokatual.classetostring() == "identificador"
			|| tokatual.nomeigual("read") || tokatual.nomeigual("write")
			|| tokatual.nomeigual("if") || tokatual.nomeigual("while")) {
		comando();
		mais_comandos();
	}
	return;
}

void sintatico::mais_comandos() {
	//; <comandos> | lambda
	token tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual(";")) {
		found(";");
		conttok++;
	} else
		erro(tokatual.getNome(), ";");
	comandos();
	return;
}

void sintatico::comando() {
	//  read (<variaveis>) |
	//  write (<variaveis>) |
	//  while <condicao> do <comandos> $ |
	//  if <condicao> then <comandos> <pfalsa> $ |
	//  ident <restoIdent>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("read")) {
		found("read");
		conttok++;
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual("(")) {
			conttok++;
			variaveis();
			tokatual = entrada_tokens[conttok];
			if (tokatual.nomeigual(")")) {
				found(")");
				conttok++;
			} else
				erro(tokatual.getNome(), ")");
		}
	} else if (tokatual.nomeigual("write")) {
		found("write");
		conttok++;
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual("(")) {
			conttok++;
			variaveis();
			tokatual = entrada_tokens[conttok];
			if (tokatual.nomeigual(")")) {
				found(")");
				conttok++;
			} else
				erro(tokatual.getNome(), ")");
		}
	} else if (tokatual.nomeigual("while")) {
		found("while");
		conttok++;
		condicao();
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual("do")) {
			found("do");
			conttok++;
			comandos();
			tokatual = entrada_tokens[conttok];
			if (tokatual.nomeigual("$")) {
				found("$");
				conttok++;
			} else
				erro(tokatual.getNome(), "$");
		} else
			erro(tokatual.getNome(), "do");
	} else if (tokatual.nomeigual("if")) {
		found("if");
		conttok++;
		condicao();
		tokatual = entrada_tokens[conttok];
		if (tokatual.nomeigual("then")) {
			found("then");
			conttok++;
			comandos();
			pfalsa();
			tokatual = entrada_tokens[conttok];
			if (tokatual.nomeigual("$")) {
				found("$");
				conttok++;
			} else
				erro(tokatual.getNome(), "$");
		} else
			erro(tokatual.getNome(), "then");
	} else if (tokatual.classetostring() == "identificador") {
		found("tipo identificador " + tokatual.getNome());
		conttok++;
		restoident();
	} else
		erro(tokatual.getNome(), "identificador, read, write, if, while.");
	return;
}

void sintatico::restoident() {
	// := <expressao> |  <lista_arg>
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual(":=")) {
		conttok++;
		found(":=");
		expressao();
	} else if (tokatual.nomeigual("(")) {
		lista_arg();
	} else {
		erro(tokatual.getNome(),
				"tipo numerico, identificador, simbolo simples");
	}
	return;
}

void sintatico::condicao() {
	// <expressao> <relacao> <expressao>
	token tokatual = entrada_tokens[conttok];

	expressao();
	relacao();
	expressao();
	return;
}
void sintatico::relacao() {
	// = | <> | >= | <= | > | <
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("=")) {
		found("=");
	} else if (tokatual.nomeigual("<>")) {
		found("<>");
	} else if (tokatual.nomeigual(">=")) {
		found(">=");
	} else if (tokatual.nomeigual("<=")) {
		found("<=");
	} else if (tokatual.nomeigual(">")) {
		found(">");
	} else if (tokatual.nomeigual("<")) {
		found("<");
	} else {
		erro(tokatual.getNome(), "operadores relacionais.");
	}
	conttok++;
	return;
}

void sintatico::expressao() {
	// <termo> <outros_termos>
	token tokatual = entrada_tokens[conttok];
	termo();
	outros_termos();
	return;
}

void sintatico::op_un() {
	// + | - | lambda
	token tokatual = entrada_tokens[conttok];

	if (tokatual.nomeigual("+")) {
		found("+");
		conttok++;
	} else if (tokatual.nomeigual("-")) {
		found("-");
		conttok++;
	}

	return;
}

void sintatico::outros_termos() {
	//<op_ad> <termo> <outros_termos> | lambda
	token tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("+") || tokatual.nomeigual("-")) {
		op_ad();
		termo();
		outros_termos();
	}
	return;
}

void sintatico::op_ad() {
	// + | -
	token tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("+")) {
		found("+");
		conttok++;
	} else if ("-") {
		found("-");
		conttok++;
	} else
		erro(tokatual.getNome(), "+ ou -");
	return;
}

void sintatico::termo() {
	// <op_un> <fator> <mais_fatores>
	token tokatual = entrada_tokens[conttok];
	op_un();
	fator();
	mais_fatores();
	return;
}

void sintatico::mais_fatores() {
	// <op_mul> <fator> <mais_fatores> | lambda
	token tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("*") || tokatual.nomeigual("/")) {
		op_mul();
		fator();
		mais_fatores();
	}
	return;
}

void sintatico::op_mul() {
	// * | /
	token tokatual = entrada_tokens[conttok];
	if (tokatual.nomeigual("*")) {
		conttok++;
		found("*");
	} else if (tokatual.nomeigual("/")) {
		conttok++;
		found("/");
	} else
		erro(tokatual.getNome(), "* ou /");
	return;
}

void sintatico::fator() {
	//  ident | numero_int | numero_real | (<expressao>)
	token tokatual = entrada_tokens[conttok];

	if (tokatual.classetostring() == "identificador") {
		conttok++;
		found("identificador " + tokatual.getNome());
	} else if (tokatual.classetostring() == "inteiro") {
		conttok++;
		found("inteiro " + tokatual.getNome());
	} else if (tokatual.classetostring() == "real") {
		conttok++;
		found("real " + tokatual.getNome());
	} else if (tokatual.nomeigual("(")) {
		conttok++;
		found("(");
	} else
		erro(tokatual.getNome(),
				"cara, como vc conseguiu. identificador, numerico, (");
	return;
}
